﻿using log4net;
using RockBus.Logging.Interfaces;
using System;
using System.Reflection;
using System.Transactions;

namespace RockBus.Logging.Log4Net
{
    public class Log4NetLogger : ILogger
    {
        public Log4NetLogger()
        {
            log4net.Config.XmlConfigurator.Configure();
            this.Log4NetLog = LogManager.GetLogger("RockBusLogger");
        }

        private ILog Log4NetLog { get; set; }

        public void Log(MethodBase currentMethod, MessageData messageData)
        {
            this.Log(currentMethod, messageData.LogLevel, MessageData.Format, new object[] {
                        messageData.MessageEvent,
                        messageData.ReceiveAddress,
                        messageData.Action,
                        messageData.CorrelationId,
                        messageData.Text,
                        messageData.DestinationAddress});
        }

        public void Log(MethodBase currentMethod, LogData logData)
        {
            switch (logData.LogLevel)
            {
                case LogLevelEnum.Error:
                    Log4NetLog.Error(logData.Text);
                    break;

                case LogLevelEnum.Warning:
                    Log4NetLog.Warn(logData.Text);
                    break;

                case LogLevelEnum.Info:
                    Log4NetLog.Info(logData.Text);
                    break;

                case LogLevelEnum.Debug:
                case LogLevelEnum.Verbose:
                    Log4NetLog.Debug(logData.Text);
                    break;

                default:
                    break;
            }
        }

        public void Log(MethodBase currentMethod, LogLevelEnum logLevel, string text, params object[] args)
        {
            switch (logLevel)
            {
                case LogLevelEnum.Error:
                    if (Log4NetLog.IsErrorEnabled)
                    {
                        text = this.FormatLogText(currentMethod, text);
                        if ((null != args) && (args.Length > 0))
                        {
                            Log4NetLog.ErrorFormat(text, args);
                        }
                        else
                        {
                            Log4NetLog.Error(text);
                        }
                    }
                    break;

                case LogLevelEnum.Warning:
                    if (Log4NetLog.IsWarnEnabled)
                    {
                        text = this.FormatLogText(currentMethod, text);
                        if ((null != args) && (args.Length > 0))
                        {
                            Log4NetLog.WarnFormat(text, args);
                        }
                        else
                        {
                            Log4NetLog.Warn(text);
                        }
                    }
                    break;

                case LogLevelEnum.Info:
                    if (Log4NetLog.IsInfoEnabled)
                    {
                        text = this.FormatLogText(currentMethod, text);
                        if ((null != args) && (args.Length > 0))
                        {
                            Log4NetLog.InfoFormat(text, args);
                        }
                        else
                        {
                            Log4NetLog.Info(text);
                        }
                    }
                    break;

                case LogLevelEnum.Debug:
                case LogLevelEnum.Verbose:
                    if (Log4NetLog.IsDebugEnabled)
                    {
                        text = this.FormatLogText(currentMethod, text);
                        if ((null != args) && (args.Length > 0))
                        {
                            Log4NetLog.DebugFormat(text, args);
                        }
                        else
                        {
                            Log4NetLog.Debug(text);
                        }
                    }
                    break;

                default:
                    break;
            }
        }

        public void Log(MethodBase currentMethod, Exception exc)
        {
            this.Log4NetLog.Error(string.Format("{0}.{1}: Exception: ", currentMethod.DeclaringType.Name, currentMethod.Name), exc);
        }

        public void LogError(MethodBase currentMethod, string text, params object[] args)
        {
            this.Log(currentMethod, LogLevelEnum.Error, text, args);
        }

        public void LogWarning(MethodBase currentMethod, string text, params object[] args)
        {
            this.Log(currentMethod, LogLevelEnum.Warning, text, args);
        }

        public void LogInfo(MethodBase currentMethod, string text, params object[] args)
        {
            this.Log(currentMethod, LogLevelEnum.Info, text, args);
        }

        public void LogDebug(MethodBase currentMethod, string text, params object[] args)
        {
            this.Log(currentMethod, LogLevelEnum.Debug, text, args);
        }

        public void LogVerbose(MethodBase currentMethod, string text, params object[] args)
        {
            this.Log(currentMethod, LogLevelEnum.Verbose, text, args);
        }

        public void Log(MethodBase currentMethod, LogLevelEnum logLevel, Transaction transaction)
        {
            if (null == transaction)
            {
                this.Log(currentMethod, logLevel, "Transaction: None");
            }
            else
            {
                this.Log(currentMethod, logLevel, "{0}, {1}, {2}, {3}",
                    transaction.TransactionInformation.CreationTime,
                    transaction.TransactionInformation.LocalIdentifier,
                    transaction.TransactionInformation.DistributedIdentifier,
                    transaction.TransactionInformation.Status);
            }
        }

        private string FormatLogText(MethodBase currentMethod, string text)
        {
            return string.Format("{0}.{1}: {2}", currentMethod.DeclaringType.Name, currentMethod.Name, text);
        }
    }
}